﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Submarines
{
    public partial class Board : UserControl
    {
        Image _img;
        Random r = new Random();
        int[] _Count = new int[4];
        protected Color _ExistColor = Color.Gold;
        protected Color _ShadowColor = Color.Black;
        protected Color _HitColor = Color.Red;

        delegate void ResultCallback(int x,int y);

        protected enum StepResult
        {
            Failed,   // step failed because button already tried
            Empty,    // tried and not hit
            Hit,      // hit a submarine
            Killed,   // destroyed
            GameOver, // game over
            Exists    // there is a submarine here
        }
        protected enum CellStatus
        {
            Normal,
            Empty,
            PartOfSubmarine,
            Hit,
            Illegal
        }

        public Board()
        {
            InitializeComponent();
        }

        public int GetSize(string s)
        {
            return int.Parse(s.Substring(1));
        }

        public bool GetShape(string s)
        {
            return (s.Substring(0, 1) == "V");
        }

        public int GetX(string s)
        {
            return (int.Parse(s.Substring(0, s.IndexOf(','))));
        }

        public int GetY(string s)
        {
            return (int.Parse(s.Substring(s.IndexOf(',') + 1, s.Length - s.IndexOf(',') - 1)));
        }

        public void InitializeSubmarines()
        {
            _Count[0] = 4;
            _Count[1] = 3;
            _Count[2] = 2;
            _Count[3] = 1;

            try
            {
                for (int x = 0; x < 10; x++)
                    for (int y = 0; y < 10; y++)
                    {
                        ((Button)tblPanel.GetControlFromPosition(x, y)).BackColor = Color.LightGray;
                        ((Button)tblPanel.GetControlFromPosition(x, y)).Tag = CellStatus.Normal;
                        ((Button)tblPanel.GetControlFromPosition(x, y)).Visible = true;
                        ((Button)tblPanel.GetControlFromPosition(x, y)).BackgroundImage = null;

                    }
            }
            catch (NullReferenceException)
            { }
        }

        public bool CheckIfKilled(int x, int y)
        {
            // is submarine vertical of horizontal
            bool Vertical = (IsCellPartOfSubmarine(x, y - 1) || IsCellPartOfSubmarine(x, y + 1));
            // set x,y to head of submarine
            if (Vertical)
                while (y > 0 && IsCellPartOfSubmarine(x, y - 1)) y--;
            else
                while (x > 0 && IsCellPartOfSubmarine(x - 1, y)) x--;
            int headx = x, heady = y;
            // check of submarine is destroyed
            if (Vertical)
            {
                do
                {
                    if ((CellStatus)((Button)tblPanel.GetControlFromPosition(x, y)).Tag == CellStatus.PartOfSubmarine) return false;
                    y++;
                } while (IsCellPartOfSubmarine(x, y));
            }
            else
            {
                do
                {
                    if ((CellStatus)((Button)tblPanel.GetControlFromPosition(x, y)).Tag == CellStatus.PartOfSubmarine) return false;
                    x++;
                } while (IsCellPartOfSubmarine(x, y));
            }
            // get size of submarine
            int size;
            x = headx;
            y = heady;
            if (Vertical)
            {
                while (IsCellPartOfSubmarine(x, y)) y++;
                size = y - heady;
            }
            else
            {
                while (IsCellPartOfSubmarine(x, y)) x++;
                size = x - headx;
            }
            // get rid of cells around the submarine
            if (Vertical)
            {
                if (heady > 0) ((Button)tblPanel.GetControlFromPosition(headx, heady - 1)).Visible = false;
                if (heady + size <= 9) ((Button)tblPanel.GetControlFromPosition(headx, heady + size)).Visible = false;
                for (y = heady - 1; y <= heady + size; y++)
                    if (y >= 0 && y <= 9)
                    {
                        if (x - 1 >= 0) ((Button)tblPanel.GetControlFromPosition(x - 1, y)).Visible = false;
                        if (x + 1 <= 9) ((Button)tblPanel.GetControlFromPosition(x + 1, y)).Visible = false;
                    }
            }
            else
            {
                if (headx > 0) ((Button)tblPanel.GetControlFromPosition(headx - 1, heady)).Visible = false;
                if (headx + size <= 9) ((Button)tblPanel.GetControlFromPosition(headx + size, heady)).Visible = false;
                for (x = headx - 1; x <= headx + size; x++)
                    if (x >= 0 && x <= 9)
                    {
                        if (y - 1 >= 0) ((Button)tblPanel.GetControlFromPosition(x, y - 1)).Visible = false;
                        if (y + 1 <= 9) ((Button)tblPanel.GetControlFromPosition(x, y + 1)).Visible = false;
                    }
            }
            return true;
        }

        public bool IsGameOver()
        {
            int hits = 0;

            for (int x = 0; x <= 9; x++)
                for (int y = 0; y <= 9; y++)
                    if ((CellStatus)((Button)tblPanel.GetControlFromPosition(x, y)).Tag == CellStatus.Hit) hits++;

            return hits == 20;
        }

        public void InstallSubmarines(bool show)
        {
            InitializeSubmarines();
            for (int a = 1; a <= 4; a++)
                for (int b = a; b <= 4; b++)
                    while (!NewSubmarine(a, show)) ;
        }
       // [STAThreadAttribute]
        void Board_Load(object sender, EventArgs e)
        {
            Button tempButton;
            for (int x = 0; x < 10; x++)
                for (int y = 0; y < 10; y++)
                {
                    tempButton = new Button();
                    tempButton.Dock = DockStyle.Fill;
                    tempButton.FlatStyle = FlatStyle.Flat;
                    tempButton.Margin = new Padding(0);
                    tempButton.Name = x.ToString() + "," + y.ToString();
                    tempButton.Size = new Size(30, 30);
                    tempButton.AllowDrop = true;
                    tempButton.MouseClick += new MouseEventHandler(Board_MouseClick);
                    tempButton.DragEnter += new DragEventHandler(Board_DragEnter);
                    tempButton.DragLeave += new EventHandler(Board_DragLeave);
                    tempButton.DragDrop += new DragEventHandler(Board_DragDrop);
                    
                    tblPanel.Controls.Add(tempButton, x, y);
                }
            InitializeSubmarines();
            SetNumbersAndLetters();
            //this.Refresh();
        }

        private void SetNumbersAndLetters()
        {
            Label l;
            
            for (int x = 1; x < 11; x++)
            {
                l = new Label();
                l.Location = new Point(x * 33, 6);

                l.ForeColor = Color.FromArgb(2, 23, 30);
                l.Size = new Size(25, 15);
                l.BackColor = Color.Transparent;
                l.Text = x.ToString();
                l.Font = new System.Drawing.Font("Tahoma", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(177)));
                this.Controls.Add(l);
            }

       
            for (int y = 1; y < 11; y++)
            {
                l = new Label();
                l.Location = new Point(8, y * 33);
                l.ForeColor = Color.FromArgb(2, 23, 30);
                l.BackColor = Color.Transparent;
                l.Size = new Size(15, 15);
                l.Text = char.ConvertFromUtf32(y + 64);
                l.Font = new System.Drawing.Font("Tahoma", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(177)));
                this.Controls.Add(l);
            }
           // this.Refresh();
        }

        void Board_MouseClick(object sender, MouseEventArgs e)
        {
            OnMouseClick(sender, e);
        }

        void Board_DragDrop(object sender, DragEventArgs e)
        {
            OnDragDrop(sender, e);
        }

        void Board_DragLeave(object sender, EventArgs e)
        {
            OnDragLeave(sender, e);
        }

        void Board_DragEnter(object sender, DragEventArgs e)
        {
            OnDragEnter(sender, e);
        }

        bool NewSubmarine(int size, bool show)
        {
            bool vertical = (r.Next(0, 2) == 1);
            int x = r.Next(0, 10);
            int y = r.Next(0, 10);

            if (SubmarineValid(x, y, size, vertical))
            {
                if (show) DrawSubmarine(x, y, size, vertical, _ExistColor);
                UpdateSubmarine(x, y, size, vertical, CellStatus.PartOfSubmarine);
                InstallSubmarine(size);
                return true;
            }
            return false;
        }

        bool IsCellPartOfSubmarine(int x, int y)
        {
            if (x < 0 || x > 9 || y < 0 || y > 9) return false;
            return (CellStatus)((Button)tblPanel.GetControlFromPosition(x, y)).Tag == CellStatus.Hit ||
                (CellStatus)((Button)tblPanel.GetControlFromPosition(x, y)).Tag == CellStatus.PartOfSubmarine;
        }

        protected virtual void OnMouseClick(object sender, MouseEventArgs e)
        {
        }

        protected virtual void OnDragDrop(object sender, DragEventArgs e)
        {
        }

        protected virtual void OnDragLeave(object sender, EventArgs e)
        {
        }

        protected virtual void OnDragEnter(object sender, DragEventArgs e)
        {
        }

        protected bool SubmarineValid(int x, int y, int size, bool Vertical)
        {
            if (_Count[size - 1] == 0) return false;

            if (Vertical)
            {
                // is submarine out of boundary
                if (10 - y < size) return false;
                // check if visible
                for (int b = y; b <= y + size - 1; b++)
                    if (((Button)tblPanel.GetControlFromPosition(x, b)).Visible == false) return false;
                // check 3 columns
                for (int a = x - 1; a <= x + 1; a++)
                    for (int b = y - 1; b <= y + size; b++)
                        if (a >= 0 && a <= 9 && b >= 0 && b <= 9)
                            if ((CellStatus)((Button)tblPanel.GetControlFromPosition(a, b)).Tag == CellStatus.PartOfSubmarine) return false;
            }
            else
            {
                // is submarine out of boundary
                if (10 - x < size) return false;
                // check if visible
                for (int a = x; a <= x + size - 1; a++)
                    if (((Button)tblPanel.GetControlFromPosition(a, y)).Visible == false) return false;
                // check 3 rows
                for (int a = x - 1; a <= x + size; a++)
                    for (int b = y - 1; b <= y + 1; b++)
                        if (a >= 0 && a <= 9 && b >= 0 && b <= 9)
                            if ((CellStatus)((Button)tblPanel.GetControlFromPosition(a, b)).Tag == CellStatus.PartOfSubmarine) return false;
            }
            return true;
        }

        protected void DrawSubmarine(int x, int y, int size, bool vertical, Color color)
        {

            if (vertical)
            {
                for (int a = y; a < y + size; a++)
                {
                    ((Button)tblPanel.GetControlFromPosition(x, a)).BackColor = color;
                    if (color == _ExistColor)
                        ((Button)tblPanel.GetControlFromPosition(x, a)).BackgroundImage = GetImage(a - y + 1, size, false);
                }
            }
            else
            {
                for (int a = x; a < x + size; a++)
                {
                    ((Button)tblPanel.GetControlFromPosition(a, y)).BackColor = color;
                    if (color == _ExistColor)
                        ((Button)tblPanel.GetControlFromPosition(a, y)).BackgroundImage = GetImage(a - x + 1, size, true);
                }
            }
        }

        protected void UpdateSubmarine(int x, int y, int size, bool vertical, CellStatus status)
        {
            if (vertical)
            {
                for (int a = y; a < y + size; a++)
                {
                    ((Button)tblPanel.GetControlFromPosition(x, a)).Tag = status;
                }
            }
            else
            {
                for (int a = x; a < x + size; a++)
                {
                    ((Button)tblPanel.GetControlFromPosition(a, y)).Tag = status;
                }
            }
        }

        protected void InstallSubmarine(int size)
        {
            _Count[size - 1]--;
        }

        protected CellStatus GetCellStatus(int x, int y)
        {
            if (x < 0 || x > 9 || y < 0 || y > 9) return CellStatus.Illegal;
            return (CellStatus)((Button)tblPanel.GetControlFromPosition(x, y)).Tag;
        }

        protected StepResult TryToHit(int x, int y)
        {
            if (x < 0 || x > 9 || y < 0 || y > 9)
                return StepResult.Failed;

            if ((CellStatus)((Button)tblPanel.GetControlFromPosition(x, y)).Tag == CellStatus.Hit)
                return StepResult.Failed;

            if (((Button)tblPanel.GetControlFromPosition(x, y)).Visible == false)
                return StepResult.Failed;

            if ((CellStatus)((Button)tblPanel.GetControlFromPosition(x, y)).Tag == CellStatus.PartOfSubmarine)
            {
                ((Button)tblPanel.GetControlFromPosition(x, y)).Tag = CellStatus.Hit;
                ((Button)tblPanel.GetControlFromPosition(x, y)).BackColor = _HitColor;
                ((Button)tblPanel.GetControlFromPosition(x, y)).BackgroundImage = global::Submarines.Properties.Resources.Explosion;
                ((Button)tblPanel.GetControlFromPosition(x, y)).BackgroundImageLayout = ImageLayout.Stretch;

                if (CheckIfKilled(x, y) == true)
                    return StepResult.Killed;
                else
                    return StepResult.Hit;
            }
            else
            {
                ((Button)tblPanel.GetControlFromPosition(x, y)).Visible = false;
                ((Button)tblPanel.GetControlFromPosition(x, y)).Tag = CellStatus.Empty;
                return StepResult.Empty;

            }
        }

        private void UpdateButton(int x, int y)
        {
            if (this.InvokeRequired)
            {
                ResultCallback d = new ResultCallback(UpdateButton);
                this.Invoke(d, new object[] { x, y });
            }
            else
            {
                ((Button)tblPanel.GetControlFromPosition(x, y)).Tag = CellStatus.Hit;
                ((Button)tblPanel.GetControlFromPosition(x, y)).BackColor = _HitColor;
                ((Button)tblPanel.GetControlFromPosition(x, y)).BackgroundImage = global::Submarines.Properties.Resources.Explosion;
                ((Button)tblPanel.GetControlFromPosition(x, y)).BackgroundImageLayout = ImageLayout.Stretch;
            }      
        }



        private Image GetImage(int i, int lenght, bool horisntal)
        {
            if (horisntal)
                switch (lenght)
                {
                    case 1:
                        _img = global::Submarines.Properties.Resources.Ship_H1;
                        break;
                    case 2:
                        switch (i)
                        {
                            case 1:
                                _img = global::Submarines.Properties.Resources.H_B;
                                break;
                            case 2:
                                _img = global::Submarines.Properties.Resources.H_F;
                                break;
                        }
                        break;

                    case 3:
                        switch (i)
                        {
                            case 1:
                                _img = global::Submarines.Properties.Resources.H_B;
                                break;
                            case 2:
                                _img = global::Submarines.Properties.Resources.H_M_t;
                                break;
                            case 3:
                                _img = global::Submarines.Properties.Resources.H_F;
                                break;
                        }
                        break;
                    case 4:
                        switch (i)
                        {
                            case 1:
                                _img = global::Submarines.Properties.Resources.H_B;
                                break;
                            case 2:
                                _img = global::Submarines.Properties.Resources.H_M_t;
                                break;
                            case 3:
                                _img = global::Submarines.Properties.Resources.H_M;
                                break;
                            case 4:
                                _img = global::Submarines.Properties.Resources.H_F;
                                break;
                        }
                        break;

                    default:
                        _img = null;
                        break;
                }
            else
            {
                switch (lenght)
                {
                    case 1:
                        _img = global::Submarines.Properties.Resources.Ship_H1;
                        break;
                    case 2:
                        switch (i)
                        {
                            case 1:
                                _img = global::Submarines.Properties.Resources.V_F;
                                break;
                            case 2:
                                _img = global::Submarines.Properties.Resources.V_B;
                                break;
                        }
                        break;

                    case 3:
                        switch (i)
                        {
                            case 1:
                                _img = global::Submarines.Properties.Resources.V_F;
                                break;
                            case 2:
                                _img = global::Submarines.Properties.Resources.V_M_t;
                                break;
                            case 3:
                                _img = global::Submarines.Properties.Resources.V_B;
                                break;
                        }
                        break;
                    case 4:
                        switch (i)
                        {
                            case 1:
                                _img = global::Submarines.Properties.Resources.V_F;
                                break;
                            case 2:
                                _img = global::Submarines.Properties.Resources.V_M_t;
                                break;
                            case 3:
                                _img = global::Submarines.Properties.Resources.V_M;
                                break;
                            case 4:
                                _img = global::Submarines.Properties.Resources.V_B;
                                break;
                        }
                        break;

                    default:
                        _img = null;
                        break;
                }

            }


            return _img;
        }

    }
}
